所謂的 Magic Number 中文翻譯是 「魔術數字」,
是指由程式設計者自己定義的某些數字,
旁人不透過註解無法了解其中的涵義,
甚至作者本人在經過一段時間後,自己也會忘了當初這個數字的用途。
像我以前常寫這樣的程式碼
if (user.Identity != 1)
{
throw new Exception("沒有權限。");
}
或
var sexName = user.Sex == 1 ? "男" : "女";
難以閱讀,無法從程式碼了解這段程式的用途,如果又沒有寫註解加上作者離職,那就真沒人知道這段程式到底在幹嘛。
而且隨著專案日漸龐大,類似的魔術數字越來越多,註解可能散落各處,或沒有跟著程式更新,這都會造成維護上的困難。
難以修改,需求變動或程式重構時,所有用到的地方都要修改,只要漏改一個地方,就會產生一個新 Bug。
在 C#
可以使用 Enum
來解決此類問題。
第一個例子,可以新增一個 Identity
的 Enum
,統一管理使用者身分的值,這樣程式可讀性佳,要改變值也只需改一個地方。
public enum Identity
{
//管理者
Admin = 1,
//一般使用者
User = 2,
}
//需判斷的地方
if (user.Identity != Identity.Admin)
{
throw new Exception("沒有權限。");
}
第二個例子,可以新增一個 Sex
的 Enum
,然後用 GetSexName
來統一管理輸出的中文。
public enum Sex
{
//男生
Male = 1,
//女生
Female = 2
}
public string GetSexName(Sex sex)
{
if (sex == Sex.Male)
{
return "男";
}
return "女";
}
//需輸出中文的地方
var sexName = GetSexName(user.Sex);
第二個例子,在 C#
還可以用 [Description("")]
Attribute 來改進。
using System.ComponentModel;
public enum Sex
{
[Description("男")]
Male = 1,
[Description("女")]
Female = 2
}
這樣不僅可以當 註解
,還可以寫一個共用的擴充方法 ToDescription
給所有的 Enum
使用,不用再為每個 Enum
寫各自的轉換函數。
public static class EnumExtenstions
{
public static string ToDescription(this Enum value)
{
return value.GetType()
.GetRuntimeField(value.ToString())
.GetCustomAttributes<System.ComponentModel.DescriptionAttribute>()
.FirstOrDefault()?.Description ?? string.Empty;
}
}
用法:
var sexName = user.Sex.ToDescription();
不指定 Enum 的值,預設由 0 開始排。
public enum Example
{
A, //0
B, //1
C //2
}
指定其中一項的值,後面的項目會依序遞增。
public enum Example
{
A = 5, //5
B, //6
C //7
}
要注意這種情形,會造成奇怪的結果,但程式不會出錯。
public enum Example
{
A = -1, //-1
B = -2, //-2
C //-1
}
var _enum = Sex.Male;
var _number = 1;
var _string = "Male";
//將 enum 轉換為 number
var val1 = (int)_enum;
//將 number 轉換為 enum
var val2 = (Sex)_number;
//將 enum 轉換為 string
var val3 = _enum.ToString();
//將 string 轉換為 enum
var val4 = (Sex)Enum.Parse(typeof(Sex), _string);
//將 enum 轉換為 JSON
var obj = new
{
abc = ABC.A
};
var json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
//{"abc":1}
可以指定的型態有
byte
、sbyte
、short
、ushort
、int
、uint
、long
、ulong
public enum Sex : byte
{
Male,
Female
}
在 Enum 加上 [Flags]
Attribute。
[Flags]
public enum ABC
{
A = 0x01,
B = 0x02,
C = 0x04
}
var abc = ABC.A | ABC.C;
var _number = (int)abc; //5
var _string = abc.ToString(); //A, C
結語:
在實務上最常看到 Magic Number
的地方就在資料庫,
所以現在我會把這種用數字代表狀態的欄位,都做出對應的 Enum 統一管理,
忘記的時候也不用到處找註解或重新閱讀程式,只要去那裡查一下馬上就知道其意義,善用 Enum
真的是最簡單提升程式碼品質的方式。
參考文章:
魔術數字 (程式設計)
Don't use Magic number in your code
CODE-enum, string, int間的轉換
Method that returns description attribute of enum value